Don't blow away checked out git repos
authorAlex Crichton <alex@alexcrichton.com>
Wed, 10 Sep 2014 14:47:11 +0000 (07:47 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 10 Sep 2014 14:47:11 +0000 (07:47 -0700)
This primarily blows away all *submodules* as well, which sometimes can be quite
large and take some time to update. Instead, re-use an existing checkout, just
reset it to the right revision if possible.

Also, move the submodule update step to occur unconditionally to account for
corrupt submodule checkouts or interrupted downloads. This update step should be
much faster than `git submodule update` because we're using libgit2, so yay!

src/cargo/sources/git/utils.rs
tests/test_cargo_compile_git_deps.rs

index 31f65bc3e9a78ab3ded234bd4b77832f5c8526f6..dfdb7e9ac65624c1f29fa5943c71b3f123e0a458 100644 (file)
@@ -202,20 +202,22 @@ impl GitDatabase {
 
     pub fn copy_to(&self, rev: GitRevision, dest: &Path)
                    -> CargoResult<GitCheckout> {
-        match git2::Repository::open(dest) {
+        let checkout = match git2::Repository::open(dest) {
             Ok(repo) => {
-                let is_fresh = match repo.revparse_single("HEAD") {
-                    Ok(head) => head.id().to_string() == rev.to_string(),
-                    _ => false,
-                };
-                if is_fresh {
-                    return Ok(GitCheckout::new(dest, self, rev, repo))
+                let checkout = GitCheckout::new(dest, self, rev, repo);
+                if !checkout.is_fresh() {
+                    try!(checkout.fetch());
+                    try!(checkout.reset());
+                    assert!(checkout.is_fresh());
                 }
+                checkout
             }
-            _ => {}
-        }
-
-        GitCheckout::clone_into(dest, self, rev)
+            Err(..) => try!(GitCheckout::clone_into(dest, self, rev)),
+        };
+        try!(checkout.update_submodules().chain_error(|| {
+            internal("failed to update submodules")
+        }));
+        Ok(checkout)
     }
 
     pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<GitRevision> {
@@ -248,14 +250,7 @@ impl<'a> GitCheckout<'a> {
     {
         let repo = try!(GitCheckout::clone_repo(database.get_path(), into));
         let checkout = GitCheckout::new(into, database, revision, repo);
-
-        try!(checkout.reset().chain_error(|| {
-            internal("failed to reset to the right revision")
-        }));
-        try!(checkout.update_submodules().chain_error(|| {
-            internal("failed to update submodules")
-        }));
-
+        try!(checkout.reset());
         Ok(checkout)
     }
 
@@ -286,6 +281,21 @@ impl<'a> GitCheckout<'a> {
         Ok(repo)
     }
 
+    fn is_fresh(&self) -> bool {
+        match self.repo.revparse_single("HEAD") {
+            Ok(head) => head.id().to_string() == self.revision.to_string(),
+            _ => false,
+        }
+    }
+
+    fn fetch(&self) -> CargoResult<()> {
+        info!("fetch {}", self.repo.path().display());
+        let url = try!(self.database.path.to_url().map_err(human));
+        let url = url.to_string();
+        try!(fetch(&self.repo, url.as_slice()));
+        Ok(())
+    }
+
     fn reset(&self) -> CargoResult<()> {
         info!("reset {} to {}", self.repo.path().display(),
               self.revision.as_slice());
index 90e66ca7a52bc7577e049b03216de8cbc80f21a4..de4c05ec117a1f3bcab6043387ad77eed7c97b46 100644 (file)
@@ -475,8 +475,7 @@ test!(two_revs_same_deps {
 
     baz.build();
 
-    // TODO: -j1 is a hack
-    assert_that(foo.cargo_process("build").arg("-j").arg("1"),
+    assert_that(foo.cargo_process("build"),
                 execs().with_status(0));
     assert_that(&foo.bin("foo"), existing_file());
     assert_that(foo.process(foo.bin("foo")), execs().with_status(0));